package pl.drypisy;

import java.awt.image.BufferedImage;

/**
 * Created with IntelliJ IDEA.
 * User: adam
 * Date: 11.01.13
 * Time: 14:31
 * To change this template use File | Settings | File Templates.
 */
public class LensCorrectionProcess extends ImageProcess {
    private int width, height;
    private double centerX, centerY;
    private BufferedImage src;
    private double a,b,c,d;

    /**
     * Sets lens correction values
     * @param a affects mostly outer pixels. Must be VERY VERY small, values around 10e-8 or less.
     * @param b this parameter should be enough for most cases. Must be around 10e-6.
     * @param c most uniform correction. Must be around 10e-3 or 10e-4
     */
    public void setValues(double a, double b, double c)
    {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = 1-(a+b+c);
    }

    @Override
    public BufferedImage process(BufferedImage img) {
        this.src = img;
        srcWidth = src.getWidth();
        srcHeight = src.getHeight();
        width = (int)(srcWidth);
        height = (int)(srcHeight);

        centerX = (width-1.0)/2.0;
        centerY = (height-1.0)/2.0;
        double xDistance = centerX;
        double yDistance = centerY;
        //Square of distance from center
        double rDest = xDistance*xDistance + yDistance*yDistance;
        double rDest_sqrt = Math.sqrt(rDest);
        double rSrc = (a*rDest*rDest_sqrt + b*rDest + c*rDest_sqrt + d) * rDest_sqrt;
        double factor = rSrc/rDest_sqrt;
        //System.out.println(factor);
        int xOffset = (int)(xDistance*factor+centerX);
        int yOffset = (int)(yDistance*factor+centerY);

        int xp = (int)((rSrc/rDest_sqrt)*(0-centerX)+centerX);
        int yp = (int)((rSrc/rDest_sqrt)*(0-centerY)+centerY);

        System.out.println(d);
        if(xp>0) xp=0;
        if(yp>0) yp=0;
        width = srcWidth -6*xp;
        height = srcHeight - 6*yp;
        //System.out.println(width + " " + height);

        BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        int[] outPixels = new int[width] ;
        int[] inPixels = src.getRGB(0, 0, srcWidth, srcHeight, null, 0, srcWidth);
        double out[] = new double[2];
        int nw,ne,sw,se;
        for(int y=0; y<height-1; ++y)
        {
            for(int x=0; x<width-1; ++x)
            {
                getOriginalCoordinates(x+3*xp,y+3*yp,out);
                int srcX = (int)Math.floor( out[0] );
                int srcY = (int)Math.floor( out[1] );
                int pix;
                if(doInterpolation) {
                    double xWeight = out[0]-srcX;
                    double yWeight = out[1]-srcY;
                    nw = getPixel( inPixels, srcX, srcY, srcWidth, srcHeight);
                    ne = getPixel( inPixels, srcX+1, srcY, srcWidth, srcHeight );
                    sw = getPixel( inPixels, srcX, srcY+1, srcWidth, srcHeight );
                    se = getPixel( inPixels, srcX+1, srcY+1, srcWidth, srcHeight );
                    pix = bilinearInterpolation(xWeight, yWeight,  nw, ne, sw, se);
                }
                else pix = getPixel(inPixels, srcX, srcY, srcWidth, srcHeight);
                outPixels[x] = pix;
            }
            dest.setRGB(0, y, width, 1, outPixels, 0, width);
        }
        return dest;
    }

    @Override
    protected void getOriginalCoordinates(int x, int y, double[] out) {
        //Distance from center
        double xDistance = centerX - x;
        double yDistance = centerY - y;
        //Square of distance from center
        double rDest = xDistance*xDistance + yDistance*yDistance;
        double rDest_sqrt = Math.sqrt(rDest);
        double rSrc = (a*rDest*rDest_sqrt + b*rDest + c*rDest_sqrt + d) * rDest_sqrt;
        double factor = Math.abs(rDest_sqrt/rSrc);
        out[0] = centerX - (xDistance*factor);
        out[1] = centerY - (yDistance * factor);
    }

}
